package com.lin.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.lin.constant.RecordConstants;
import com.lin.customEnum.RecordStatus;
import com.lin.entity.po.Record;
import com.lin.entity.po.User;
import com.lin.entity.query.RecordQuery;
import com.lin.entity.vo.*;
import com.lin.exception.BookStatusException;
import com.lin.exception.NoBorrowRecordException;
import com.lin.exception.UserStatusException;
import com.lin.mapper.RecordMapper;
import com.lin.service.IBookService;
import com.lin.service.IRecordService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lin.service.IUserService;
import com.lin.utils.RedisSerializerUtil;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;


@Service
public class RecordServiceImpl extends ServiceImpl<RecordMapper, Record> implements IRecordService {
    @Resource
    private RedisSerializerUtil redisUtil;
    @Resource
    private IUserService userService;

    @Resource
    private IBookService bookService;

    /**
     * 查询指定图书的借阅记录, 如果该图书被借阅, 返回用户信息
     * 先查询Redis中是否存在对应数据,
     * 如果存在则直接返回, 否则查询数据库并返回
     *
     * @param bookId 图书ID
     * @return 已被借阅的用户信息 or null
     */
    @Override
    public RecordVO borrowBook(Integer bookId) throws JsonProcessingException {
        // 当前图书信息key
        String RecordInfoKey = RecordConstants.RECORD_INFO_KEY_PREFIX + bookId;

        // 先查看Redis中是否已有数据
        RecordVO recordRedis = redisUtil.get(RecordInfoKey, RecordVO.class);

        // 如果Redis中存在数据, 直接返回
        if (recordRedis != null)
            return BeanUtil.copyProperties(recordRedis, RecordVO.class);

        // 预定义返回结果
        RecordVO recordVO;

        // Redis中不存在数据, 查询数据库并添加到Redis中
        if (bookId != null) {
            Record record = lambdaQuery().eq(Record::getBookId, bookId).one();
            recordVO = BeanUtil.copyProperties(record, RecordVO.class);
            // 该图书已被借阅, 查询借阅者信息封装到recordVO中
            if (record.getStatus() == 0) {
                UserVO userVO = userService.getUserById(record.getUserId());
                recordVO.setUserVO(userVO);
                redisUtil.set(RecordInfoKey, recordVO); // 将数据添加到Redis中
            } else {
                recordVO.setUserVO(null);
            }
            return recordVO;
        }
        return null;
    }

    /**
     * 借阅记录 过期、未过期、归还
     * 先查询Redis中是否存在对应数据,
     * 如果存在则直接返回, 否则查询数据库并返回
     * @param recordId 借阅记录ID
     * @return RecordStatus
     */
    @Override
    public RecordStatus isExpired(Integer recordId) throws JsonProcessingException {
        // 借阅状态key
        String recordStatusKey = RecordConstants.RECORDS_STATUS_KEY_PREFIX + recordId;

        // 先查看Redis中是否有对应信息
        RecordStatus recordStatus = redisUtil.get(recordStatusKey, RecordStatus.class);

        // 如果Redis中存在对应信息, 直接返回
        if (recordStatus != null)
            return recordStatus;

        // Redis中不存在对应信息, 数据库中查询借阅记录并添加到Redis
        Record record = lambdaQuery().eq(Record::getId, recordId).one();

        if (record == null)
            throw new NoBorrowRecordException("借阅记录不存在");

        // 判断借阅状态 0-借阅中 1-已归还
        boolean status = record.getStatus() == 0;
        if (status) {
            // 借阅时间、过期时间、当前时间
            LocalDateTime borrowTime = record.getBorrowTime();
            LocalDateTime expireTime = borrowTime.plusDays(RecordConstants.EXPIRE_TIME);
            LocalDateTime currentTime = LocalDateTime.now();

            // 判断当前时间是否超过或等于借阅时间
            if (expireTime.isAfter(currentTime))
                recordStatus = RecordStatus.NOT_EXPIRED;
            else if (expireTime.isEqual(currentTime) || expireTime.isBefore(currentTime))
                recordStatus = RecordStatus.EXPIRED;
            else
                recordStatus = RecordStatus.LOST;
            redisUtil.set(recordStatusKey, recordStatus); // 将数据添加到Redis中
        } else{
            recordStatus = RecordStatus.RETURNED;
        }
        return recordStatus;
    }

    /**
     * 查询当前用户借阅记录
     * 先查询Redis中是否存在对应数据,
     * 如果存在则直接返回, 否则查询数据库并返回
     *
     * @param username 用户名
     * @return List<RecordVO>
     */
    @Override
    public List<RecordVO> getCurrentUserRecords(String username) throws JsonProcessingException {
        // 用户名为空或空字符串, 抛出异常
        if (username == null || username.trim().isEmpty())
            return null;

        // 当前用户借阅信息key
        String currentUserRecordKey = RecordConstants.CURRENT_USER_RECORD_INFO_KEY_PREFIX + username;

        // 先查看Redis中是否有对应信息
        List<RecordVO> recordVOS = redisUtil.get(currentUserRecordKey, new TypeReference<>() {});

        // 如果Redis中存在对应信息, 直接返回
        if (recordVOS != null)
            return recordVOS;

        // 获取用户ID
        User user = userService.lambdaQuery().eq(User::getUsername, username).one();
        if (user == null)
            return null;

        Integer userId = user.getId();

        // 转换为UserVO
        UserVO userVO = BeanUtil.copyProperties(user, UserVO.class);

//        List<RecordVO> recordVOS = new ArrayList<>();

        // 用户id为null或<=0, 返回null
        if (userId == null || userId <= 0)
            return null;

        // 查询用户的借阅记录
        List<Record> recordList = lambdaQuery().eq(Record::getUserId, userId).list();

        if (recordList != null && !recordList.isEmpty()) {
            // 使用流处理, 将Record转换为RecordVO
            recordVOS = recordList.stream().map(record -> {
                RecordVO recordVO = BeanUtil.copyProperties(record, RecordVO.class);
                recordVO.setUserVO(userVO);
                return recordVO;
            }).collect(Collectors.toList());

            /* for循环处理, 将Record转换为RecordVO
            for (Record record: recordList) {
                RecordVO recordVO = BeanUtil.copyProperties(record, RecordVO.class);
                recordVO.setUserVO(userVO);
                recordVOS.add(recordVO);
            }*/
        }
        redisUtil.set(currentUserRecordKey, recordVOS);
        return recordVOS;
    }

    /**
     * 分页查询所有借阅记录
     * 先查询Redis中是否存在对应数据,
     * 如果存在则直接返回, 否则查询数据库并返回
     *
     * @param recordQuery 查询参数
     * @return List<RecordVO>
     */
    @Override
    public PageVO<RecordVO2> getAllRecords(RecordQuery recordQuery) throws JsonProcessingException {
        // 分页参数
        int pageNum = recordQuery.getPage();
        int pageSize = recordQuery.getPageSize();
        Page<Record> page = Page.of(pageNum, pageSize);

        // 借阅状态key
        String recordStatusKey = RecordConstants.RECORDS_STATUS_KEY_PREFIX
                + '_' + pageNum + '_' + pageSize;

        // 查看Redis中是否存在对应数据, 如果存在则直接返回
        PageVO<RecordVO2> recordVO2PageVO = redisUtil.get(recordStatusKey, new TypeReference<>() {});

        // 如果Redis中存在对应数据, 直接返回
        if (recordVO2PageVO != null)
            return recordVO2PageVO;

        // 根据创建时间排序
        if (recordQuery.getIsAsc())
            page.addOrder(OrderItem.asc("borrow_time"));
        else
            page.addOrder(OrderItem.desc("borrow_time"));

        // 分页查询
        Page<Record> p = page(page);

        // 获取记录
        List<Record> records = p.getRecords();

        // 预声明返回结果
        PageVO<RecordVO2> pageVO = new PageVO<>();

        // 设置分页信息
        pageVO.setPageNum((int) page.getCurrent());
        pageVO.setPageSize((int) page.getSize());
        pageVO.setTotal((int) page.getTotal());

        // 转换为RecordVO2
        if (CollUtil.isNotEmpty(records)) {
            List<RecordVO2> recordVO2s = BeanUtil.copyToList(records, RecordVO2.class);
            // 获取借阅记录的借阅人信息
            for (RecordVO2 record : recordVO2s) {
                Integer userId = record.getUserId(); // 获取借阅人ID
                Integer bookId = record.getBookId(); // 获取图书ID
                UserVO userVO = null; // 获取借阅人信息
                BookVO bookVO = null;// 获取图书信息

                try {
                    userVO = userService.getUserById(userId);
                    bookVO = bookService.getBookById(bookId);
                } catch (UserStatusException | BookStatusException e) {
                    continue; // 如果用户被冻结, 跳过当前记录
                }

                record.setUserVO(userVO); // 设置借阅人信息
                record.setBookVO(bookVO); // 设置图书信息
            }
            pageVO.setList(recordVO2s); // 设置记录列表
            redisUtil.set(recordStatusKey, pageVO);
        }
        return pageVO;
    }
}
